package definition

import (
	"codejy/analysis"
	"codejy/analysis/codeanalysis"
	"codejy/analysis/lineanalysis"
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"math"
	"strconv"
	"strings"
)

type TypeDefanalysis struct {
	//优先级
	priority int
}

func init() {
	RegisterDefinition(&TypeDefanalysis{priority: 0})
}

func (t *TypeDefanalysis) GetPriority() int {
	return t.priority
}

func (t TypeDefanalysis) ParseDefinition(codes *[]structdef.LineCodeDefinition, realityFilePath string) {
	typesDef(codes, realityFilePath)
}
func typesDef(currentLineCodes *[]structdef.LineCodeDefinition, filePath string) {
	//记录需要初始化的实例
	var initShare []string
	var annotations = make(map[string]map[string]string)

	for i := 0; i < len(*currentLineCodes); {
		currentLineCode := (*currentLineCodes)[i]
		if (*currentLineCodes)[i].LineCodeType == lineanalysis.TypeDefine {
			//向上找注解直到遇到}或者没有了
			if i > 0 {
				for j1 := i - 1; j1 >= 0; j1-- {
					currentLineCode1 := (*currentLineCodes)[j1]
					//如果是}，则结束
					if currentLineCode1.LineContent == "}" {
						break
					}
					//判断是否是注解
					if analysis.IsAnnotation(currentLineCode1.LineContent) {
						annotationName, annotationParams := utils.ExtractAnnotation(currentLineCode1.LineContent)
						annotations[annotationName] = annotationParams
						//删除排除的行
						*currentLineCodes = append((*currentLineCodes)[:j1], (*currentLineCodes)[j1+1:]...)
						i--
						continue
					}
				}

			}
			var codelines []structdef.LineCodeDefinition
			//截取类型名
			typeName := (*currentLineCodes)[i].LineContent[strings.Index((*currentLineCodes)[i].LineContent, "type")+4:]
			//排除结尾{
			typeName = typeName[0:strings.Index(typeName, "{")]
			var isShare bool
			//判断开头是否是share
			if strings.HasPrefix(typeName, "share") {
				isShare = true
				//去除share
				typeName = typeName[5:]
			}
			//类型以逗号分割
			split := strings.Split(typeName, ",")
			typeName = split[0]
			//判断类型名是否合法
			globalfunc.ExecuteFunc("IsVariableNameLegal", typeName)
			//获取父类型,父类型是从下标1开始的
			var parentTypeName []string
			if len(split) > 1 {
				parentTypeName = split[1:]
			}
			//删除排除的行
			*currentLineCodes = append((*currentLineCodes)[:i], (*currentLineCodes)[i+1:]...)
			//解析类型定义,从类型定义开始，往下找到类型体结束
			var num = 1
			for j := i; j < len(*currentLineCodes); {
				currentLineCode = (*currentLineCodes)[j]
				//添加需要解析的代码
				codelines = append(codelines, currentLineCode)
				//删除排除的行
				*currentLineCodes = append((*currentLineCodes)[:j], (*currentLineCodes)[j+1:]...)
				if strings.HasSuffix(currentLineCode.LineContent, "{") {
					num++
				}
				if strings.HasPrefix(currentLineCode.LineContent, "}") {
					num--
				}
				if num == 0 { //类型体结束
					//获取类型内部所有字段
					getTypeProperties := GetTypeProperties(store.MainThreadStore, &codelines)
					//获取所有方法
					getMethods := GetBehaviorMethodsDef(&codelines, typeName)
					//注册类型
					store.RegisterTypeDefinition(filePath, typeName, structdef.NewTypeDefinition(typeName, parentTypeName, isShare, getTypeProperties, getMethods, annotations))
					//清空注解
					annotations = make(map[string]map[string]string)
					//将父类型添加到类型内部
					if len(parentTypeName) > 0 {
						MergeParentType(typeName, parentTypeName, filePath)
					}
					if isShare { //如果是共享类型,那么提前实例化到存储中
						//拿到类型定义
						typeDefinition := store.GetTypeDefinition(filePath, typeName)
						if typeDefinition == nil {
							panic("类型未定义:" + typeName)
						}
						var pd = false
						//执行所有父,初始化init方法
						for i1 := 0; i1 < math.MaxInt; i1++ {
							_, p := typeDefinition.Methods["init"+"_"+strconv.Itoa(i1)]
							if p {
								pd = true
							} else { //父类型中没有init方法
								break
							}
						}
						//执行初始化init方法
						_, p := typeDefinition.Methods["init"]
						if p {
							pd = true
						}
						if pd { //如果有init方法
							initShare = append(initShare, typeName)
						}
					}
					break
				}
			}
		} else {
			//继续下一行
			i++
		}
	}
	//初始化共享类型, 共享类型是在所有类型解析完毕后才初始化,否则会出现类型未定义 @Todo: 后续优化有问题 不应该在这里初始化,因为在第一次解析的时候在调用init方法, 可以参照java的类加载机制 这样就能解决循环依赖的问题
	for _, typeName := range initShare {
		//拿到类型定义
		typeDefinition := store.GetTypeDefinition(filePath, typeName)
		if typeDefinition == nil {
			panic("类型未定义:" + typeName)
		}

		addr := utils.InstantiateAddressGeneratoSafe() //生成实例地址
		store.NweStatusRestore(store.MainThreadStore, func() string {
			store.MainThreadStore.CurrentInstanceAddress = addr
			scope := store.MainThreadStore.CurrentEnv
			//初始化属性
			properties := globalfunc.ExecuteFunc("InitProperties", store.MainThreadStore, typeName, typeDefinition.Properties, []string{}, filePath).(map[string]structdef.VarDefinition)
			//注册实例变量
			store.RegisterInstance(store.MainThreadStore, addr, properties)
			//执行所有父,初始化init方法
			for i1 := 0; i1 < math.MaxInt; i1++ {
				definition, p := typeDefinition.Methods["init"+"_"+strconv.Itoa(i1)]
				if p {
					globalfunc.ExecuteFunc("ExecuteTypeMethod", store.MainThreadStore, "init", definition, []string{}) //执行方法
				} else { //父类型中没有init方法
					break
				}
			}
			//执行初始化init方法
			definition, p := typeDefinition.Methods["init"]
			if p {
				globalfunc.ExecuteFunc("ExecuteTypeMethod", store.MainThreadStore, "init", definition, []string{}) //执行方法
			}
			//将共享类型注册到全局变量作用域中
			store.RegisterVariableScope(store.MainThreadStore, scope, structdef.NewVarDefinitionValue(typeName, addr, codeanalysis.TypeShareInstanceGlobal))
			return ""
		})
	}
}

// 获取类型内部所有字段,遇到方法定义结束
func GetTypeProperties(threadStore *structdef.ThreadStore, codelines *[]structdef.LineCodeDefinition) []structdef.PropertiesDefinition {
	var properties []structdef.PropertiesDefinition
	length := len(*codelines)
	var annotations = make(map[string]map[string]string)
	for i := 0; i < length; i++ {
		currentLineCode := (*codelines)[i]
		if currentLineCode.LineCodeType == lineanalysis.DEF { //遇到方法定义结束
			break
		}
		//判断是否是注解
		if analysis.IsAnnotation(currentLineCode.LineContent) {
			annotationName, annotationParams := utils.ExtractAnnotation(currentLineCode.LineContent)
			annotations[annotationName] = annotationParams
			continue
		}
		//以逗号分割
		split := strings.Split(currentLineCode.LineContent, ",")
		for i2 := range split {
			//排除空
			if split[i2] == "" {
				continue
			}
			//判断类型名是否合法
			globalfunc.ExecuteFunc("IsVariableNameLegal", split[i2])
			//添加属性
			definition := structdef.NewPropertiesDefinition(split[i2],
				-1,
				currentLineCode.LineCodeFile, currentLineCode.LineNum, annotations)
			properties = append(properties, definition)
		}
		//清空注解
		annotations = make(map[string]map[string]string)
	}
	return properties

}

// 获取父类型,然后将父类型的属性和方法添加到当前类型中
func MergeParentType(currentTypeName string, parentTypes []string, scope string) {
	//获取类型
	currentType := store.GetTypeDefinition(scope, currentTypeName)
	//获取父类型
	length := len(parentTypes)
	for i := 0; i < length; i++ {
		parentName := parentTypes[i]
		var parentTypeDefinition *structdef.TypeDefinition
		//判断是否有点号,有点号说明是其他文件的类型
		if strings.Contains(parentName, ".") {
			//截取其他文件名称
			fileName := parentName[0:strings.Index(parentName, ".")]
			//通过文件名称获取文件实际映射路径
			fileNamePath := store.GetImportFile(scope, fileName)
			//截取类型名
			parentTypeName := parentName[strings.Index(parentName, ".")+1:]
			//获取类型定义
			parentTypeDefinition = store.GetTypeDefinition(fileNamePath, parentTypeName)
		} else {
			//获取当前父的类型
			parentTypeDefinition = store.GetTypeDefinition(scope, parentName)
		}
		//将父类型的属性添加到当前类型中,如果有重复的属性则不添加
		currentType.Properties = append(currentType.Properties, parentTypeDefinition.Properties...)
		//去重
		utils.RemoveDuplicate[structdef.PropertiesDefinition](&currentType.Properties, 1, func(a structdef.PropertiesDefinition, b structdef.PropertiesDefinition) bool {
			return a.Name == b.Name
		})
		//添加父类方法到当前类型中,如果有重复的方法则不添加
		var initNum = 0
		for key, v := range parentTypeDefinition.Methods {
			_, p := currentType.Methods[key]
			if p {
				//判断父中是否是init方法,如果是init方法,那么就修改父init的名称
				if key == "init" {
					key = key + "_" + strconv.Itoa(initNum)
					initNum++
				} else {
					continue
				}
			}
			currentType.Methods[key] = v
		}
	}
	//修改类型定义
	store.UpdateTypeDefinition(scope, currentTypeName, currentType)

}

// 注册类型行为方法
func GetBehaviorMethodsDef(currentLineCodes *[]structdef.LineCodeDefinition, typeName string) map[string]structdef.BehaviorDefinition {
	var annotations = make(map[string]map[string]string)
	var methods = make(map[string]structdef.BehaviorDefinition)
	for i := 0; i < len(*currentLineCodes); i++ {
		currentLineCode := (*currentLineCodes)[i]
		//判断是否是注解
		if analysis.IsAnnotation(currentLineCode.LineContent) {
			annotationName, annotationParams := utils.ExtractAnnotation(currentLineCode.LineContent)
			annotations[annotationName] = annotationParams
			//删除排除的行
			*currentLineCodes = append((*currentLineCodes)[:i], (*currentLineCodes)[i+1:]...)
			i--
			continue
		}
		if currentLineCode.LineCodeType == lineanalysis.DEF { //行为定义
			var codelines []structdef.LineCodeDefinition
			//截取函数名
			funcName := currentLineCode.LineContent[strings.Index(currentLineCode.LineContent, "def")+3:]
			//排除结尾{
			funcName = funcName[0:strings.Index(funcName, "{")]
			//判断类型方法名称是否合法
			globalfunc.ExecuteFunc("IsVariableNameLegal", funcName)
			//解析函数定义 ,从函数定义开始，往下找到函数体结束
			var num = 1
			for j := i + 1; j < len(*currentLineCodes); j++ {
				currentLineCode = (*currentLineCodes)[j]
				codelines = append(codelines, currentLineCode)
				if strings.HasSuffix(currentLineCode.LineContent, "{") {
					num++
				}
				if strings.HasPrefix(currentLineCode.LineContent, "}") {
					num--
				}
				if num == 0 { //函数体结束
					//跳过最后}
					codelines = codelines[:len(codelines)-1]
					handleFilePath := store.MainThreadStore.HandleFilePath
					codelines = structdef.AnalyseLineCodeDefinitions(store.MainThreadStore, codelines, handleFilePath)
					methods[funcName] = structdef.NewBehaviorDefinition(typeName, funcName, codelines, annotations)
					//清空注解
					annotations = make(map[string]map[string]string)
					i = j
					break
				}

			}

		}
	}
	return methods
}
